package com.liz.elasticSearch.demo.utils;


import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.MultiSearchRequest;
import org.elasticsearch.action.search.MultiSearchResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Component
public class ElasticsearchUtil {


    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticsearchUtil.class);

    @Resource(name = "restHighLevelClient")
    private RestHighLevelClient restHighLevelClient;

    private static RestHighLevelClient client;

    private static ObjectMapper mapper = new ObjectMapper();

    /**
     * @PostContruct是spring框架的注解 spring容器初始化的时候执行该方法
     */
    @PostConstruct
    public void init() {
        client = this.restHighLevelClient;
    }

    /**
     * 创建索引
     *
     * @param index
     * @return
     */
    public static boolean createIndex(String index) {
        //index名必须全小写，否则报错
        CreateIndexRequest request = new CreateIndexRequest(index);
        try {
            CreateIndexResponse indexResponse = client.indices().create(request, RequestOptions.DEFAULT);
            if (indexResponse.isAcknowledged()) {
                LOGGER.info("创建索引成功");
            } else {
                LOGGER.info("创建索引失败");
            }
            return indexResponse.isAcknowledged();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return false;
    }

    /**
     * 插入数据
     *
     * @param index
     * @param type
     * @param object
     * @return
     */
    public static String addData(String index, String type, String id, JSONObject object) {
        IndexRequest indexRequest = new IndexRequest(index, type, id);
        try {
            indexRequest.source(mapper.writeValueAsString(object), XContentType.JSON);
            IndexResponse indexResponse = client.index(indexRequest);
            return indexResponse.getId();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 检查索引
     *
     * @param index
     * @return
     * @throws IOException
     */
    public static boolean checkIndexExist(String index) {
        try {
            Response response = client.getLowLevelClient().performRequest("HEAD", index);
            boolean exist = response.getStatusLine().getReasonPhrase().equals("OK");
            return exist;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }


    /**
     * ElasticSearch7.X实现单字段的高亮搜索
     * 原文地址 https://www.jianshu.com/p/c798281869c4
     *
     * @param index
     * @param fieldName
     * @param searchWords
     * @return
     * @throws IOException
     */
    public static List<Map<String, Object>> matchQueryWithHighLight(String index, String fieldName, String searchWords) throws IOException {
        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        QueryBuilder queryBuilder = QueryBuilders.matchQuery(fieldName, searchWords);
        sourceBuilder.query(queryBuilder);

        //设置高亮字段
        HighlightBuilder highlightBuilder = new HighlightBuilder().field(fieldName).preTags("<font color='red'>").postTags("</font>");
        sourceBuilder.highlighter(highlightBuilder);
        sourceBuilder.from(0); // 其实位置
        sourceBuilder.size(10); // 每页数据条数
        searchRequest.source(sourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        List<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField nameHighlight = highlightFields.get(fieldName);
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            if (nameHighlight != null) {
                Text[] fragments = nameHighlight.getFragments();
                String _address = "";
                for (Text text : fragments) {
                    _address += text;
                }
                sourceAsMap.put(fieldName, _address);
                list.add(sourceAsMap);
            }
        }
        return list;

    }


    /**
     * 原文链接：https://blog.csdn.net/john1337/article/details/103126485
     *
     * @param index
     * @param fieldNames
     * @param searchWords
     * @return
     * @throws IOException
     */
    public static List<Map<String, Object>> multiMatchQueryWithHighLight(String index, List<String> fieldNames, String searchWords) {
        if (CollectionUtils.isEmpty(fieldNames)) {
            return null;
        }
        MultiSearchRequest request = new MultiSearchRequest();
        SearchRequest searchRequest = null;
        for (String fieldName : fieldNames) {
            searchRequest = new SearchRequest();
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchQuery(fieldName, searchWords));
            searchRequest.source(searchSourceBuilder);
            searchRequest.indices(index);
            request.add(searchRequest);
        }

        try {
            MultiSearchResponse response = client.msearch(request, RequestOptions.DEFAULT);
            response.forEach(t -> {
                SearchResponse resp = t.getResponse();
                Arrays.stream(resp.getHits().getHits()).forEach(i -> {
                    System.out.println(i.getId());
                    System.out.println(i.getIndex());
                    System.out.println(i.getSourceAsString());
                    System.out.println(i.getShard());
                });
                System.out.println(resp.getHits().totalHits);
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取低水平客户端
     *
     * @return
     */
    public static RestClient getLowLevelClient() {
        return client.getLowLevelClient();
    }

}
